/**************************************************************************//**
 * @file    AttributeHelper.c
 * @author  İsmail SEZEN (email: sezenismail@gmail.com)
 * @date    02-08-2009
 *
 * <b>Description</b>
 *
 * This is a helper module to handle the attributes defined in netCDF file.\n
 *
 * Copyright (C) 2009 İsmail SEZEN
 *
 * <b>License</b>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************/

/* Include Directives *///{
#include <stdio.h>
#include <stdlib.h>
#include <netcdf.h>
#include <array_helper.h>
#include "AttributeHelper.h"
//}

/* Macros *///{
/*! \brief A small Error macro prints the error to standart output */
#define PRINT_ERR(e){printf("Error: %s\n", nc_strerror(e));}
/*! @brief Generic attribute handling macro that gets a pointer to the attribute value associated with a type */
#define GET_ATT_P_internal(type) ((type*)get_att_p(ncid,varid,attName))
/*! @brief Generic attribute handling macro that gets a pointer to the attribute value associated with a type.
 *  @note This macro differs from the \ref GET_ATT_P_internal macro by a NULL test */
#define GET_ATT_internal(type)/**/ \
{ \
	type* r = NULL; \
	if( (r= GET_ATT_P_internal(type) ) == NULL ) exit(EXIT_FAILURE); \
	return *r; \
} \
//}

/*! @brief GENERIC attribute value handling function
 *
 *  This funtion is a generic attribute function and
 *  returns a void pointer to the attribute value.
 *  It's possible to cast the returning pointer to
 *  correct type. Other functions in this file
 *  basically uses this function.
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a void pointer to the memory location */
void* get_att_p(int ncid, int varid, const char* attName) {
	int status;
	size_t v_len;
	nc_type xtypep;
	/* find out how much space is needed for attribute value */
	if ((status = nc_inq_att (ncid, varid, attName, &xtypep, &v_len)) == NC_NOERR) {
		/* allocate required space before retrieving values */
		size_t size = (xtypep == NC_CHAR) ? v_len+1 : v_len * nctypelen(xtypep);
		void* attribute = xmalloc(size);
		 if ((status = nc_get_att(ncid,varid,attName,attribute)) == NC_NOERR){
		 	if(xtypep == NC_CHAR) {
		 		char* att = (char*)attribute;
		 		att[v_len] = '\0';
		 	}
			return attribute;
		 }
	}
	PRINT_ERR(status);
	return NULL;
}

/*! @name Attribute Functions returns pointer by type
 *  These functions uses \ref GET_ATT_P_internal function internally
 *  and returns a pointer to the attribute value.
 */
//@{//{

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a char pointer to the memory location */
char* get_string_att_p(int ncid,int varid,const char* attName) {
	return GET_ATT_P_internal(char);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a float pointer to the memory location */
float* get_float_att_p(int ncid,int varid,const char* attName) {
	return GET_ATT_P_internal(float);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a double pointer to the memory location */
double* get_double_att_p(int ncid, int varid,const char* attName) {
	return GET_ATT_P_internal(double);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a short pointer to the memory location */
short* get_short_att_p(int ncid, int varid,const char* attName) {
	return GET_ATT_P_internal(short);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return A NULL pointer if specified attribute can not be handled otherwise
 *          returns a int pointer to the memory location */
int* get_int_att_p(int ncid, int varid,const char* attName) {
	return GET_ATT_P_internal(int);
}

//}//@}

/*! @name Attribute Functions returns value by type
 *  These functions uses \ref GET_ATT_internal function internally
 *  and returns the attribute value due to type.
 */
//@{//{

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return Returns a float value associated with attribute */
float get_float_att(int ncid,int varid, const char* attName) {
	GET_ATT_internal(float);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return Returns a double value associated with attribute */
double get_double_att(int ncid,int varid, const char* attName) {
	GET_ATT_internal(double);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return Returns a short value associated with attribute */
short get_short_att(int ncid,int varid, const char* attName) {
	GET_ATT_internal(short);
}

/*! @brief Gets the attribute value associated with a variable
 *  @param[in] *ncid is netCDF file identifier
 *  @param[in] *varid is variable identifier in the netCDF file
 *  @param[in] *attName is pointer to Attribute Name
 *  @return Returns a int value associated with attribute */
int get_int_att(int ncid,int varid, const char* attName) {
	GET_ATT_internal(int);
}

//}//@}
